From: Tim Deegan Date: Fri, 12 Aug 2011 10:29:24 +0000 (+0100) Subject: Passthrough: disable bus-mastering on any card that causes an IOMMU fault. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~9970 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22Dat/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22Dat?a=commitdiff_plain;h=d30a9b356bd3a51191004c2da26615a97e91af91;p=xen.git Passthrough: disable bus-mastering on any card that causes an IOMMU fault. This stops the card from raising back-to-back faults and live-locking the CPU that handles them. Signed-off-by: Tim Deegan Acked-by: Wei Wang2 Acked-by: Allen M Kay --- diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c index bbf8908d74..6bff49ada5 100644 --- a/xen/drivers/passthrough/amd/iommu_init.c +++ b/xen/drivers/passthrough/amd/iommu_init.c @@ -461,7 +461,7 @@ static hw_irq_controller iommu_msi_type = { static void parse_event_log_entry(u32 entry[]) { - u16 domain_id, device_id; + u16 domain_id, device_id, bdf, cword; u32 code; u64 *addr; char * event_str[] = {"ILLEGAL_DEV_TABLE_ENTRY", @@ -496,6 +496,18 @@ static void parse_event_log_entry(u32 entry[]) "%s: domain = %d, device id = 0x%04x, " "fault address = 0x%"PRIx64"\n", event_str[code-1], domain_id, device_id, *addr); + + /* Tell the device to stop DMAing; we can't rely on the guest to + * control it for us. */ + for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ ) + if ( get_requestor_id(bdf) == device_id ) + { + cword = pci_conf_read16(PCI_BUS(bdf), PCI_SLOT(bdf), + PCI_FUNC(bdf), PCI_COMMAND); + pci_conf_write16(PCI_BUS(bdf), PCI_SLOT(bdf), + PCI_FUNC(bdf), PCI_COMMAND, + cword & ~PCI_COMMAND_MASTER); + } } else { diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 23c6f2f1eb..91e8c3b3b4 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -884,7 +884,7 @@ static void iommu_page_fault(int irq, void *dev_id, while (1) { u8 fault_reason; - u16 source_id; + u16 source_id, cword; u32 data; u64 guest_addr; int type; @@ -917,6 +917,14 @@ static void iommu_page_fault(int irq, void *dev_id, iommu_page_fault_do_one(iommu, type, fault_reason, source_id, guest_addr); + /* Tell the device to stop DMAing; we can't rely on the guest to + * control it for us. */ + cword = pci_conf_read16(PCI_BUS(source_id), PCI_SLOT(source_id), + PCI_FUNC(source_id), PCI_COMMAND); + pci_conf_write16(PCI_BUS(source_id), PCI_SLOT(source_id), + PCI_FUNC(source_id), PCI_COMMAND, + cword & ~PCI_COMMAND_MASTER); + fault_index++; if ( fault_index > cap_num_fault_regs(iommu->cap) ) fault_index = 0;